
#if NO_CMDLINE
#else

#include "CmdParser.h"
#include "Debug.h"

Bool Str_toUl(const uint8 *s, uint32* pUint32)
{
	Bool bRet = False;
	unsigned long value;
	int i = 0;
	int bytes = 0;

	value = 0;

	if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
	{
		s++;
		s++;
		//String convert to Hex
		while (*s != '\0') 
		{
			bRet = True;
			if(bytes++ >= 8)
			{
				bRet = False;
				goto End;
			}
			
			if (*s >= '0' && *s <= '9')
			{
				i = *s - '0';
			}
			else if (*s >= 'a' && *s <= 'f')
			{
				i = *s - 'a' + 0xa;
			}
			else if (*s >= 'A' && *s <= 'F')
			{
				i = *s - 'A' + 0xa;
			}
			else
			{
				bRet = False;
				goto End;
			}
			
			value = (value << 4) + i;
			s++;
		}
	}
	else
	{
		//String convert to decimal
		while (*s != '\0') 
		{
			bRet = True;
			if(bytes++ >= 10)
			{
				bRet = False;
				goto End;
			}
			
			if (*s >= '0' && *s <= '9')
			{
				value = value * 10 + (*s - '0');
			}
			else
			{
				bRet = False;
				goto End;
			}
			s++; 
		}
	}

End:
	*pUint32 = value;

	return bRet;
}

void CmdParser_Dump(CmdParser* pCmdParser)
{
	int i = 0;
	const static char* pState[] = 
	{
		 "PARSE_NAME"
		,"PARSE_ARGS1"
		,"PARSE_ARGS2"
		,"PARSE_ARGS3"
		,"PARSE_ARGS4"
		,"PARSE_END"
	};
	
	TRACE_LEVEL(TRACE_SHELL,("m_State=[%s]\n", pState[pCmdParser->m_State]));
	TRACE_LEVEL(TRACE_SHELL,("m_MaxLen=[%d]\n", pCmdParser->m_MaxLen));
	TRACE_LEVEL(TRACE_SHELL,("m_ArgsCount=[%d]\n", pCmdParser->m_ArgsCount));
	TRACE_LEVEL(TRACE_SHELL,("m_nIndex=[%d]\n", pCmdParser->m_nIndex));

	TRACE_LEVEL(TRACE_SHELL,("m_Cmd=[%s]\n", pCmdParser->m_Cmd));
	//TRACE_LEVEL(TRACE_SHELL,("m_String=[%s]\n", pCmdParser->m_String));
	for(i = 0; i < pCmdParser->m_ArgsCount; i++)
	{
		int j = 0;
		Bool bFlag = True;

		for(j = 0; j < pCmdParser->m_stringArgsCount; j++)
		{
			if(pCmdParser->m_Args[i] == (uint32)pCmdParser->m_String[j])
			{
				bFlag = False;
				TRACE_LEVEL(TRACE_SHELL,("m_Args[%d]=[%s]\n", i, pCmdParser->m_Args[i]));
				continue;
			}
		}

		if(bFlag)
		{
			TRACE_LEVEL(TRACE_SHELL,("m_Args[%d]=[0x%08x]\n", i, pCmdParser->m_Args[i]));
		}
	}
}

int CmdParser_Parse(CmdParser* pCmdParser, const uint8* str, uint8 len)
{
	int i = 0;

	for(i = 0; i < len; i++, str++)
	{
		if(pCmdParser->m_isEcho)
		{
			if(pCmdParser->m_nIndex == 0 && PARSE_NAME == pCmdParser->m_State)
			{
				TRACE_LEVEL(TRACE_SHELL,(">"));
			}

			if(*str >= 0x20 && *str <= 0x7e)
			{
				TRACE_LEVEL(TRACE_SHELL,("%c", *str));
			}
		}
		
		if(ENTER_KEY == *str)
		{
			if(pCmdParser->m_isEcho)
			{
				//TRACE_LEVEL(TRACE_SHELL,("\n"));
			}
			pCmdParser->m_State = PARSE_END;
			goto End;
		}

		if(pCmdParser->m_ErrorCode)
		{
			continue;
		}

		if(pCmdParser->m_isParseString)
		{
			if('"' == *str)
			{
				pCmdParser->m_isParseString = False;
				pCmdParser->m_pData = Null;
			}
			else
			{
				if(pCmdParser->m_nIndex < pCmdParser->m_MaxLen)
				{
					if(Null == pCmdParser->m_pData || *str < 0x20 || *str > 0x7e)
					{
						continue;
					}
					
					pCmdParser->m_pData[pCmdParser->m_nIndex++] = *str;
				}
				else
				{
					pCmdParser->m_ErrorCode = pCmdParser->m_State + 1;
					pCmdParser->m_pData = Null;
					continue;
				}
			}
		}
		else if(')' == *str)
		{
			if(pCmdParser->m_pData == pCmdParser->m_NumStr)
			{
				if(pCmdParser->m_nIndex == 0 && PARSE_ARGS1 == pCmdParser->m_State)
				{
					pCmdParser->m_ArgsCount = 0;
				}
				else
				{
					pCmdParser->m_ArgsCount++;
					if(!Str_toUl(pCmdParser->m_NumStr, &pCmdParser->m_Args[pCmdParser->m_State - PARSE_ARGS1]))
					{
						pCmdParser->m_ErrorCode = pCmdParser->m_State + 1;
						pCmdParser->m_pData = Null;
					}
				}
			}
			else
			{
				pCmdParser->m_ArgsCount++;
			}
			pCmdParser->m_State = PARSE_END;
			pCmdParser->m_pData = Null;

			continue;
		}
		else if('(' == *str)
		{
			if(PARSE_NAME != pCmdParser->m_State) continue;
			
			pCmdParser->m_State++;
			Assert(pCmdParser->m_State <= PARSE_END);
			pCmdParser->m_nIndex = 0;
			pCmdParser->m_MaxLen = MAX_ARGS_LEN;
			pCmdParser->m_pData = pCmdParser->m_NumStr;
			memset(pCmdParser->m_NumStr, 0, sizeof(pCmdParser->m_NumStr));
		}		
		else if(' ' == *str)
		{
			continue;
		}		
		else if('"' == *str)
		{
			if(PARSE_NAME == pCmdParser->m_State) continue;

			pCmdParser->m_isParseString = True;
			pCmdParser->m_nIndex = 0;
			pCmdParser->m_MaxLen = MAX_STRING_LEN;
			pCmdParser->m_pData = &pCmdParser->m_String[pCmdParser->m_stringArgsCount][0];
			pCmdParser->m_Args[pCmdParser->m_State - PARSE_ARGS1] = (uint32)&pCmdParser->m_String[pCmdParser->m_stringArgsCount];
			
			pCmdParser->m_stringArgsCount++;
			if(pCmdParser->m_stringArgsCount > MAX_STRING_ARGS)
			{
				pCmdParser->m_ErrorCode = EC_TOO_MANY_STRING_PARAM;
				pCmdParser->m_pData = Null;
			}

		}		
		else if(',' == *str)
		{
			if(PARSE_NAME == pCmdParser->m_State) continue;

			Assert(pCmdParser->m_State >= PARSE_ARGS1);

			if(pCmdParser->m_pData == pCmdParser->m_NumStr)
			{
				if(!Str_toUl(pCmdParser->m_NumStr, &pCmdParser->m_Args[pCmdParser->m_State - PARSE_ARGS1]))
				{
					pCmdParser->m_ErrorCode = pCmdParser->m_State + 1;
					pCmdParser->m_pData = Null;
				}
			}
			
			pCmdParser->m_State++;
			Assert(pCmdParser->m_State <= PARSE_END);
			pCmdParser->m_ArgsCount++;
			pCmdParser->m_nIndex = 0;
			pCmdParser->m_pData = pCmdParser->m_NumStr;
			memset(pCmdParser->m_NumStr, 0, sizeof(pCmdParser->m_NumStr));
			pCmdParser->m_MaxLen = MAX_ARGS_LEN;

			if(PARSE_END == pCmdParser->m_State)
			{
				pCmdParser->m_ErrorCode = pCmdParser->m_State + 1;
				pCmdParser->m_pData = Null;
				continue;
			}
		}		
		else if(*str >= 0x20 && *str <= 0x7e)
		{			
			if(Null == pCmdParser->m_pData)
			{
				continue;
			}
			
			if(pCmdParser->m_nIndex < pCmdParser->m_MaxLen)
			{
				pCmdParser->m_pData[pCmdParser->m_nIndex++] = *str;
			}
		}
		else
		{
			continue;
		}
	}

End:	
	return i;
}

void CmdParser_Excute(CmdParser* pCmdParser)
{
	int i = 0;
	const CmdLine* pCmdLine = Null;

	const char* pErrStr[] = 
	{
		""
		,"Function name error."
		,"arguments 1 error."
		,"arguments 2 error."
		,"arguments 3 error."
		,"arguments 4 error."
		,"too many arguments."
		,"String arguments is too many."
	};
	
	if(PARSE_END != pCmdParser->m_State)
	{
		return ;
	}

	TRACE_LEVEL(TRACE_SHELL,("\n"));
	if(pCmdParser->m_ErrorCode)
	{
		TRACE_LEVEL(TRACE_SHELL,("Error: %s\n", pErrStr[pCmdParser->m_ErrorCode]));
		return ;
	}

	for(i = 0; i < pCmdParser->m_CmdTableCount; i++)
	{
		Assert(pCmdParser->m_pCmdTable);
		pCmdLine = &pCmdParser->m_pCmdTable[i];
		
		if(0 == strcmp((char*)pCmdParser->m_Cmd, (char*)pCmdLine->m_pCmdParser))
		{
			pCmdLine->CmdProc(pCmdParser);
			return ;
		}
	}

	//if(pCmdParser->m_nIndex)
	{
		TRACE_LEVEL(TRACE_SHELL,("Error: Unknown [%s]\n", pCmdParser->m_Cmd));
	}
}

void CmdParser_Reset(CmdParser* pCmdParser)
{
	pCmdParser->m_ErrorCode = PARSE_NAME;
	
	pCmdParser->m_State = PARSE_NAME;
	pCmdParser->m_MaxLen = MAX_FUNCTION_NAME;
	pCmdParser->m_ArgsCount = 0;
	pCmdParser->m_nIndex = 0;
	pCmdParser->m_stringArgsCount = 0;
	pCmdParser->m_isParseString = False;
	pCmdParser->m_pData = pCmdParser->m_Cmd;

	memset(pCmdParser->m_Cmd, 0, sizeof(pCmdParser->m_Cmd));
	memset(pCmdParser->m_pData, 0, sizeof(pCmdParser->m_pData));
	memset(pCmdParser->m_Args, 0, sizeof(pCmdParser->m_Args));
	memset(pCmdParser->m_String, 0, sizeof(pCmdParser->m_String));
	memset(pCmdParser->m_NumStr, 0, sizeof(pCmdParser->m_NumStr));
}

void CmdParser_Init(CmdParser* pCmdParser, const CmdLine* pCmdTable, uint8 cmdTableCount, Bool isEcho)
{
	memset(pCmdParser, 0, sizeof(CmdParser));
	
	g_dwDebugLevel |= TRACE_SHELL;

	CmdParser_Reset(pCmdParser);
	pCmdParser->m_isEcho = isEcho;

	pCmdParser->m_pCmdTable = pCmdTable;
	pCmdParser->m_CmdTableCount = cmdTableCount;
}

#endif //#if NO_CMDLINE

